// 对象仓库的操作
import _clearStore from "./store-clear";

// model 的添加、修改、设置、获取、删除
import _addModel from "./model-add"; // 添加一个对象
import _putModel from "./model-put"; // 修改一个对象
import _setModel from "./model-set"; // 修改一个对象
import _getModel from "./model-get"; // 获取一个对象，或者全部（不能查询）
import _delModel from "./model-delete"; // 获取一个对象，或者全部（不能查询）
import _getCount from "./model-count"; // 获取仓库里的数量

// 对象查询
import _listAll from "./list-index";
import _listPager from "./list-pager";

// 初始化和事务
import _beginInit from "./begin-init";
import _beginTran from "./begin-tran"; // 事务
/**
 * indexedDB 的 help，基础功能的封装
 * * 打开数据库，建立对象仓库，获取连接对象，实现增删改查
 * * info 的结构：
 * * * dbFlag: '' // 数据库标识，区别不同的数据库
 * * * dbConfig: { // 连接数据库
 * * * * dbName: '数据库名称',
 * * * * ver: '数据库版本',
 * * * },
 * * * stores: {
 * * * * storeName: { // 对象仓库名称
 * * * * * id: 'id', // 主键名称
 * * * * * index: { // 可以不设置索引
 * * * * * * name: ture, // key：索引名称；value：是否可以重复
 * * * * * }
 * * * * }
 * * * },
 * * * init: (help) => {} // 完全准备好之后的回调函数
 */
export default class indexedDBHelp {
  constructor(info) {
    this.myIndexedDB =
      window.indexedDB ||
      window.webkitIndexedDB ||
      window.mozIndexedDB ||
      window.msIndexedDB;
    if (!this.myIndexedDB) {
      console.log("您的浏览器不支持IndexedDB");
    }
    // 数据库名称和版本号
    this._info = {
      dbName: info.dbConfig.dbName,
      ver: info.dbConfig.ver,
    };
    // 记录连接数据库的对象， IDBDatabase 类型，因为open是异步操作，所以不能立即获得。
    this._db = null;
    // 记录仓库状态。new：新库或者版本升级后；old：有对象仓库了。
    this._storeState = "pending";

    /**
     * 注册回调事件。
     * * 如果组件读写 indexedDB 的时还没有准备好的话，
     * * 可以来注册一个事件，等准备好了之后回调。
     */
    this._regCallback = [];

    // 打开数据库，异步操作，大概需要几毫秒的时间。
    this.dbRequest = this.myIndexedDB.open(this._info.dbName, this._info.ver);

    // 第一次，或者版本升级时执行，根据配置信息建立表
    this.dbRequest.onupgradeneeded = (event) => {
      this._storeState = "new"; //新仓库
      const db = event.target.result;
      //   console.log("【2】新建或者升级数据库 onupgradeneeded --- ", db);
      for (const key in info.stores) {
        const store = info.stores[key];
        if (db.objectStoreNames.contains(key)) {
          //  已经有仓库，验证一下是否需要删除原来的仓库
          if (store.isClear) {
            // 删除原对象仓库，没有保存数据
            db.deleteObjectStore(key);
            // 建立新对象仓库
            const objectStore = db.createObjectStore(key, {
              keyPath: store.id,
            });
            //建立索引
            for (const key2 in store.index) {
              const unique = store.index[key2];
              objectStore.createIndex(key2, key2, { unique });
            }
          }
        } else {
          // 没有对象建立
          const objectStore = db.createObjectStore(key, {
            keyPath: store.id, //自动创建主键
          });
          //建立索引
          for (const key2 in store.index) {
            const unique = store.index[key2];
            objectStore.createIndex(key2, key2, { unique });
          }
        }
      }
    };

    this.dbRequest.onsuccess = (event) => {
      this._db = event.target.result; //dbRequest.result
      //   console.log("【1】成功打开数据库 onsuccess --- ", this._db);
      // 修改状态
      if (this._storeState === "pending") {
        this._storeState = "old";
      }
      // 调用初始化回调
      if (typeof info.init === "function") {
        info.init(this);
        // 调用主键注册回调
        this._regCallback.forEach((fn) => {
          if (typeof fn === "function") {
            fn();
          }
        });
      }
    };
    // 处理出错信息
    this.dbRequest.onerror = (event) => {
      // 出错
      console.log("打开数据库出错：", event.target.error);
    };
  }

  // versionchange 全能事务

  // 初始化时批量添加对象的事务
  beginInit(storeName) {
    return _beginInit(this, storeName);
  }
  // 读写的事务
  beginWrite(storeName) {
    return _beginTran(this, storeName, "readwrite");
  }

  // 只读的事务
  beginReadonly(storeName) {
    return _beginTran(this, storeName, "readonly");
  }
  /**
   * 删掉整个库
   */
  deleteDB() {
    // 定义一个 Promise 的实例
    const objectPromise = new Promise((resolve, reject) => {
      // 删掉整个库
      const request = this.myIndexedDB.deleteDatabase(this._info.dbName);
      request.onsuccess = (e) => {
        // 没有触发
        // console.log("删除整个库成功");
        resolve(e);
      };
      request.onblocked = (e) => {
        // 这个就会触发
        // console.log("删除数据库的 blocked:", e);
        // Close connections here
        resolve(e);
      };
      request.onerror = (e) => {
        // console.log('删除数据库的 error:', e)
      };
    });
    return objectPromise;
  }

  /**
   * 清空一个对象仓库的全部对象
   * @param {string} storeName 对象仓库名称
   * @param {IDBTransaction} tran 事务，可以为 null
   * @returns
   */
  clearStore(storeName, tran = null) {
    return _clearStore(this, storeName, tran);
  }

  /**
   * 添加一个对象
   * @param {*} storeName
   * @param {*} model
   * @param {*} tranRequest
   * @returns
   */
  addModel(storeName, model, tranRequest = null) {
    return _addModel(this, storeName, model, (tranRequest = null));
  }
  /**
   * 获取一个对象，或者仓库的全部对象
   * @param {string} storeName 对象仓库名称
   * @param {number} id null：获取仓库的全部对象；其他：对象ID值
   * @param {IDBTransaction} tran 事务，可以为 null
   * @returns
   */
  getModel(storeName, id = null, tran = null) {
    return _getModel(this, storeName, id, tran);
  }

  /**
   *
   * @param {string} storeName 对象仓库名称
   * @param {object} model 要修改的对象
   * @param {number} id 对象主键ID
   * @param {IDBTransaction} tran tran 事务，可以为 null
   * @returns
   */
  putModel(storeName, model, id = null, tran = null) {
    return _putModel(this, storeName, model, id, tran);
  }

  /**
   * 添加或者修改一个对象
   * @param {string} storeName 对象仓库名称
   * @param {object} model 要添加或者修改的对象
   * @param {number} id 对象主键ID，判断有无的依据
   * @param {IDBTransaction} tran 事务，可以为 null
   * @returns
   */
  setModel(storeName, model, id = null, tran = null) {
    return _setModel(this, storeName, model, id, tran);
  }

  /**
   * 删除一个对象
   * @param {string} storeName 对象仓库名称
   * @param {object} id id 或者 model 要删除的对象
   * @param {IDBTransaction} tran 事务，可以为 null
   * @returns
   */
  delModel(storeName, id, tran = null) {
    return _delModel(this, storeName, id, tran);
  }

  /**
   * 获取对象仓库里全部对象的数量
   * @param {string} storeName 对象仓库名称
   * @param {IDBTransaction} tran 事务，可以为 null
   * @returns
   */
  getCount(storeName, tran = null) {
    return _getCount(this, storeName, tran);
  }

  /**
   * 获取一个仓库的全部对象
   * @param {string} storeName 对象仓库名称
   * @param {object} query 查询条件
   * @param {IDBTransaction} tran 事务，可以为 null
   * @returns
   */
  getList(storeName, query = {}, tran = null) {
    return _listAll(this, storeName, query, tran);
  }
  /**
   * 获取一个仓库的全部对象
   * @param {string} storeName 对象仓库名称
   * @param {object} query 查询条件
   * @param {IDBTransaction} tran 事务，可以为 null
   * @returns
   */
  listPager(storeName, query = {}, tran = null) {
    return _listPager(this, storeName, query, tran);
  }
}
